using System;
using System.Collections.Generic;
using System.Text;
using ElteIk.RoboSoccer.Core.Physics;

namespace ElteIk.RoboSoccer.Core
{
	/// <summary>
	/// The goal object. It will look like a 'U' shape rotated left or right.
	/// </summary>
	public class Goal : Physics.Polygon
	{
		#region Lifecycle methods

		/// <summary>
		/// Constructs a goal with a specific heading and thickness.
		/// </summary>
		/// <param name="center"></param>
		/// <param name="heading"></param>
		/// <param name="depth"></param>
		/// <param name="size"></param>
		/// <param name="thickness"></param>
		public Goal(Vector2D center, Vector2D heading, float depth, float size, float thickness)
			: base(center)
        {
			this.depth = depth;
			this.size = size;
			this.center = center;
			this.Heading = heading.Normalized;
			this.IsMovable = false;
            SetupGoalPoints(depth, size, heading, thickness);
        }

		/// <summary>
		/// Constructs a goal heading to the X axis and with thickness of size / 10.
		/// </summary>
		/// <param name="center"></param>
		/// <param name="depth"></param>
		/// <param name="size"></param>
		public Goal(Vector2D center, float depth, float size)
			: this(center, Vector2D.X_Axis, depth, size, size / 10.0f)
		{
		}

		#endregion

		#region Public Properties

		private Vector2D center;
		public Vector2D Center
		{
			get { return center; }
		}

        private float depth;

		/// <summary>
        /// The depth (height) of the goal. 
		/// </summary>
		public float Depth
        {
            get { return depth; }
        }

        private float size;
		/// <summary>
		/// The size (width) of the goal.
		/// </summary>
		public float Size
        {
            get { return size; }
		}

		#endregion

		#region Goal construction

		/// <summary>
		/// Constructs the goal heading to the given vector.
		/// </summary>
		/// <param name="depth"></param>
		/// <param name="size"></param>
		/// <param name="heading"></param>
		/// <param name="thickness"></param>
		private void SetupGoalPoints(float depth, float size, Vector2D heading, float thickness)
        {
			Vector2D headingPerp = heading.Perpendicular;
			Vector2D startPoint = heading * depth / 2 + headingPerp * size / 2;
			Points.Add(startPoint);
			Points.Add(startPoint - heading * depth);
			Points.Add(startPoint - heading * depth - headingPerp * size);
			Points.Add(startPoint - headingPerp * size);
			Points.Add(startPoint - headingPerp * (size - thickness));
			Points.Add(startPoint - heading * (depth - thickness) - headingPerp * (size - thickness));
			Points.Add(startPoint - heading * (depth - thickness) - headingPerp * (thickness));
			Points.Add(startPoint - headingPerp * thickness);
		}

		#endregion

		#region Ball-related functions

        /// <summary>
        /// Returns true if the ball is inside the goal.
        /// </summary>
        /// <param name="ball"></param>
        /// <returns></returns>
		public bool Contains(Ball ball)
		{
            return (Math.Abs(ball.Position.X - center.X) < depth / 2 && Math.Abs(ball.Position.Y - center.Y) < size / 2);
		}

		#endregion
	}
}
